// ==UserScript==
// @name         大乐透
// @namespace    http://tampermonkey.net/
// @version      v2024.05.09.01
// @description  try to take over the world!
// @author       Lic
// @match        https://view.lottery.sina.com.cn/lotto/pc_zst/index?lottoType=dlt*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=sina.com.cn
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';
    //**** 参数-start ****//
    let is_multiple=false;
    let exclude_last_period=[2,3]; //排除最近n天
    let probability_error=4; //出现概率容错（%）
    //****  参数-end  ****//

    let arr1 = [];
    let arr2 = [];
    let r_ball_num = [];
    let select1 = document.createElement('select');
    let select2 = document.createElement('select');

    //初始化筛选项
    function init_arr(){
        for(let a=0;a<=5;a++){
            for(let b=0;b<=5-a;b++){
                if(a+b==5){
                    arr2.push([a+':'+b,a<=1||b<=1?1:0]);
                }
                for(let c=0;c<=5-b;c++){
                    if(a+b+c==5){
                        arr1.push([a+':'+b+':'+c,a+b<=1||a+c<=1||b+c<=1?1:0]);
                    }
                }
            }
        }
    }

    //获取子字符串个数
    function countSubstring(str, subStr) {
        const regex = new RegExp(subStr, 'g');
        return (str.match(regex) || []).length;
    }

    //数组扁平化
    function flatten(arr) {
        return arr.reduce(function(prev, next){
            return prev.concat(Array.isArray(next) ? flatten(next) : next)
        }, [])
    }

    //数组平均值
    function average(arr) {
        return arr.reduce((sum, current) => sum + current, 0) / arr.length;
    }

    //数组求和
    function sum(arr){
        return arr.reduce((sum, current) => sum + current, 0);
    }

    //获取奇数或偶数个数
    function getOddOrEvenNumber(a,b) {
        let result = 0;
        for(let i = 0;i < a.length;i++) {
            if((b==1&&a[i]%2 != 0)||(b==2&&a[i]%2 == 0)){
                result++;
            }
        }
        return result;
    }

    //从数组中随机获取num个元素，不重复
    function getRandomUnique(arr, num) {
        const result = new Set();
        while (result.size < num) {
            const index = Math.floor(Math.random() * arr.length);
            result.add(arr[index]);
        }
        return [...result];
    }

    //获取红球分区的奇数的下标
    function get_ball_index(s1_s2_arr,odd_s1_s2_arr,start_index,end_index){
        let res_arr = [];
        let temp_arr = s1_s2_arr.slice(start_index,end_index);
        for(let i=0;i<odd_s1_s2_arr.length;i++){
            if(temp_arr.includes(odd_s1_s2_arr[i])){
                res_arr.push(temp_arr.indexOf(odd_s1_s2_arr[i]))
            }
        }
        return res_arr;
    }

    //清空
    function clear(i){
        let presele = document.querySelector("#presele_"+i);
        [...presele.querySelectorAll("td:not([class='br01']):not([class='presele_tit'])")].forEach(item=> {item.className=null});
    }

    //计算属性
    function calculate(i,isRe=false){
        let presele = document.querySelector("#presele_"+i);

        let sum_ball = [...presele.querySelectorAll("td[class$='ball']")].map(item=> parseInt(item.innerText)).reduce((a,b,c,d)=>a+b);

        let red_ball = [...presele.querySelectorAll("td.realball")].map(item=> parseInt(item.innerText));
        let sub_ball = red_ball[red_ball.length-1]-red_ball[0];

        let area_ball = [];
        let a_ball = [...presele.querySelectorAll("td[class='realball'],td[class='br01']")].map(item=> item.className);
        let a_ball_str = a_ball.slice(1,-2).join('').split('br01');
        for(let a=0;a<a_ball_str.length;a++){
            area_ball.push(countSubstring(a_ball_str[a],'realball'));
        }
        let area_ball_str = area_ball.join(':');

        let oddOrEvenNumber = getOddOrEvenNumber(red_ball,1)+':'+getOddOrEvenNumber(red_ball,2)

        let res_presele_tit = [sum_ball,sub_ball,area_ball_str,oddOrEvenNumber];

        if(isRe){
            return res_presele_tit;
        }else{
            let presele_tit = [...presele.querySelectorAll("td[class='presele_tit']")].slice(1,);
            for(let b=0;b<presele_tit.length;b++){
                presele_tit[b].innerText=res_presele_tit[b];
            }
        }
    }

    //筛选
    function screen(i){
        let presele = document.querySelector("#presele_"+i);
        let presele_tit = [...presele.querySelectorAll("td[class='presele_tit']")].slice(3,);

        select1.options.add(new Option('0:0:0','0:0:0'));
        arr1.forEach((item)=>{
            let option = new Option(item[0],item[0]);
            if(item[1]==1)option.className='bg12';
            select1.options.add(option);
        });
        presele_tit[0].append(select1);

        select2.options.add(new Option('0:0','0:0'));
        arr2.forEach((item)=>{
            let option = new Option(item[0],item[0]);
            if(item[1]==1)option.className='bg11';
            select2.options.add(option);
        });
        presele_tit[1].append(select2);
    }

    //筛选计算
    function screen_ball(i){
        let s1=select1.value;
        let s2=select2.value;

        if(s1=='0:0:0'){
            s1 = arr1[Math.floor(Math.random() * arr1.length)][0];
        }
        if(s2=='0:0'){
            s2 = arr2[Math.floor(Math.random() * arr2.length)][0];
        }

        let presele = document.querySelector("#presele_"+i);
        let period = get_period(exclude_last_period[0]);

        let s1_arr = s1.split(':').map(item=>parseInt(item));
        let s2_arr = s2.split(':').map(item=>parseInt(item));

        let s1_s2_arr = [1,2,3,4,5];
        let odd_s1_s2_arr = getRandomUnique(s1_s2_arr,s2_arr[0])
        let odd_arrs = {
            'r1':get_ball_index(s1_s2_arr,odd_s1_s2_arr,0,s1_arr[0]),
            'r2':get_ball_index(s1_s2_arr,odd_s1_s2_arr,s1_arr[0],s1_arr[0]+s1_arr[1]),
            'r3':get_ball_index(s1_s2_arr,odd_s1_s2_arr,s1_arr[0]+s1_arr[1],5),
            'b':[]
        };

        let r_ball = presele.querySelectorAll("td:not([class='br01']):not([class='presele_tit'])");
        let rBallArea = getBallArea();

        let r1 = getAreaNums(rBallArea,'r1',s1_arr[0],period.red,odd_arrs);
        let r2 = getAreaNums(rBallArea,'r2',s1_arr[1],period.red,odd_arrs);
        let r3 = getAreaNums(rBallArea,'r3',s1_arr[2],period.red,odd_arrs);
        let b = getAreaNums(rBallArea,'b',2,period.blue);

        console.log(odd_arrs,r1,r2,r3,b)

        for(let j=0;j<r_ball.length;j++){
            r_ball[j].className=null;
            if(j<12&&s1_arr[0]>0){
                if(r1.includes(parseInt(r_ball[j].innerText))){
                    r_ball[j].className='realball';
                }
            }else if(j>=12&&j<24&&s1_arr[1]>0){
                if(r2.includes(parseInt(r_ball[j].innerText))){
                    r_ball[j].className='realball';
                }
            }else if(j>=24&&j<35&&s1_arr[2]>0){
                if(r3.includes(parseInt(r_ball[j].innerText))){
                    r_ball[j].className='realball';
                }
            }else if(j>=35){
                if(b.includes(parseInt(r_ball[j].innerText))){
                    r_ball[j].className='blueball';
                }
            }
        }
    }

    //获取区域 出现次数 反向概率
    function getBallArea(){
        let rBallArea = {'r1':{},'r2':{},'r3':{},'b':{}};
        for(let i=0;i<r_ball_num.length;i++){
            if(i<12){
                rBallArea.r1[i+1]=100-r_ball_num[i];
            }else if(i>=12&&i<24){
                rBallArea.r2[i+1]=100-r_ball_num[i];
            }else if(i>=24&&i<35){
                rBallArea.r3[i+1]=100-r_ball_num[i];
            }else if(i>=35){
                rBallArea.b[i-34]=100-r_ball_num[i];
            }
        }
        return rBallArea;
    }

    //获取区域随机球
    function getAreaNums(rBallArea,area,ball_num,exclude_ball_arr,odd_arrs={'r1':[],'r2':[],'r3':[],'b':[]}){
        let res_ball = [];
        let area_ball = rBallArea[area];
        let odd_arr = odd_arrs[area];
        for(let i=0;i<ball_num;i++){
            let odd_ball = []

            if(odd_arr.includes(i)){
                odd_ball=[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34];
            }else{
                odd_ball=[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35];
            }
            if(area=='b'){
                odd_ball=[];
            }

            let new_exclude_ball_arr = exclude_ball_arr.concat(odd_ball).concat(res_ball);
            let new_area_ball = {};
            let area_ball_sum=0;
            for(let k in area_ball){
                if(!new_exclude_ball_arr.includes(parseInt(k))){
                    area_ball_sum+=area_ball[k];
                }
            }
            for(let k in area_ball){
                if(!new_exclude_ball_arr.includes(parseInt(k))){
                    new_area_ball[k]=area_ball[k]/area_ball_sum
                }
            }
            res_ball.push(parseInt(weightedRand(new_area_ball)));
        }
        return res_ball;
    }

    //权重随机数
    function weightedRand(spec) {
        let i, sum=0, r=Math.random();
        for (i in spec) {
            sum += spec[i];
            if (r <= sum) return i;
        }
    }

    //获取最近n期
    function get_period(n){
        if(n==0)return {'red':[],'blue':[]};
        //近n期
        let last_period = [...document.querySelector("#cpdata").querySelectorAll("tr")].slice(0-n);
        //近n期红球
        let chartball01 = last_period.map((item)=>{
            return [...item.querySelectorAll("td[class='chartball01'],td[class='chartball20']")].map(item => parseInt(item.innerText));
        });
        //近n期蓝球
        let chartball02 = last_period.map((item)=>{
            return [...item.querySelectorAll("td[class='chartball02']")].map(item => parseInt(item.innerText));
        });
        return {'red':flatten(chartball01),'blue':flatten(chartball02)};
    }

    //排除最近n期
    function exclude_period(n){
        let period = get_period(n);
        let presele_1 = document.querySelector("#presele_1");
        let exclude_last_period_row = presele_1.cloneNode(true);
        exclude_last_period_row.id='presele_period_row';
        exclude_last_period_row.querySelectorAll("td")[0].innerText='排除最近'+n+'期';
        let r_ball = exclude_last_period_row.querySelectorAll("td:not([class])");
        for(let i=0;i<r_ball.length;i++){
            if(i<35){
                if(period.red.includes(parseInt(r_ball[i].innerText))){
                    r_ball[i].className='blueball';
                }
            }else{
                if(period.blue.includes(parseInt(r_ball[i].innerText))){
                    r_ball[i].className='realball';
                }
            }
        }
        presele_1.parentNode.prepend(exclude_last_period_row);
        screen('period_row');
    }

    //出现概率 参数容错率默认为error=0
    function get_count_probability(error=0){
        let one = document.querySelector("#now_gross > tr:nth-child(1)");
        let count_probability = one.cloneNode(true);
        count_probability.querySelectorAll("td")[0].innerText='出现概率（%）';
        let r_ball = [...count_probability.querySelectorAll("td:not([class])")].slice(1,-4);
        r_ball.map((item)=>{
            let num = (parseInt(item.innerText)/document.querySelector("#cpdata").querySelectorAll("tr").length)*100;
            item.innerText = Math.round(num);
            r_ball_num.push(num);
        });
        r_ball.map((item)=>{
            if(parseInt(item.innerText)>=(average(r_ball_num)+error)){
                item.className = 'realball';
            }else if(parseInt(item.innerText)<(average(r_ball_num)-error)){
                item.className = 'blueball';
            }else{
                item.className = 'chartball06';
            }
        });
        one.parentNode.prepend(count_probability);
    }

    //绑定预选行计算事件
    function bind_func(){
        for(let i=1;i<=3;i++){
            let presele = document.querySelector("#presele_"+i).querySelectorAll("td")[0];
            presele.innerText = '-'+presele.innerText+'-';
            let button1 = document.createElement('a');
            button1.innerText = '计算';
            button1.style.color = 'blue';
            button1.onclick=function(){
                calculate(i);
            };
            presele.prepend(button1);
            let button2 = document.createElement('a');
            button2.innerText = '筛选';
            button2.style.color = 'blue';
            button2.onclick=function(){
                screen_ball(i);
                calculate(i);
            };
            presele.append(button2);presele.append('-');
            let button3 = document.createElement('a');
            button3.innerText = '清空';
            button3.style.color = 'blue';
            button3.onclick=function(){
                clear(i);
            };
            presele.append(button3);
        }
    }

    //程序入口
    function start(){
        //初始化
        init_arr();

        get_count_probability(probability_error);

        if(is_multiple){
            for(let n=exclude_last_period[0];n>=exclude_last_period[1];n--){
                exclude_period(n);
            }
        }else{
            exclude_period(exclude_last_period[0]);
        }

        bind_func();
    }

    start();

    // Your code here...
})();